<?php


namespace modules\es;


use lib\tools\logs\DbLog;
use modules\tracing\zipkin\ZipkinTracing;

/**
 * Class EnglishEs
 * @method static array index(\lib\entity\es\EntityEnglish $entity)
 * @method static array search($type, $keyword, $p, $size)
 * @method static mixed delete($id)
 * @package modules\es
 */
class EnglishEs extends \lib\tools\elasticsearch\CoreEs
{
    const _INDEX_ = 'english_search';

    private static function main($call, $params)
    {
        $tracing = ZipkinTracing::start(ZipkinTracing::SERVERNAME_ES);

        try {
            $span = $tracing->span(ZipkinTracing::SPAN_ES_EXECUTE, [[$call, $params]]);

            $client = self::getInstance();

            array_unshift($params, $client);

            return call_user_func_array($call, $params);

        } catch (\Exception $e) {

            $code = $e->getCode();
            $file = $e->getFile();
            $line = $e->getLine();
            $message = $e->getMessage();

            DbLog::error('es操作异常', compact('call','params', 'code', 'file', 'line', 'message'));

            throw $e;

        } finally {
            if (isset($span)) $span->finish();
        }
    }

    public static function getInfo($id)
    {
        $params = [
            'index' => self::_INDEX_,
            'id'    => $id
        ];

        $info = null;

        try {

            $response = self::getInstance()->get($params);

            $info = $response['_source'] ?? null;

        } catch (\Exception $e) {

            DbLog::error(compact('e'));
        }

        return $info;
    }

    private static function _index(\Elasticsearch\Client $client, \lib\entity\es\EntityEnglish $entity)
    {
        $params = [
            'index' => self::_INDEX_,
            'id' => $entity->id,
            'body' => $entity
        ];

        return $client->index($params);
    }

    private static function _delete(\Elasticsearch\Client $client, $id)
    {
        $params = [
            'index' => self::_INDEX_,
            'id'    => $id
        ];

        return $client->delete($params);
    }

    private static function _search(\Elasticsearch\Client $client, $type, $keyword, $p, $size)
    {

        $sort = [
            '_score' => 'DESC',
            'addTime' => 'DESC'
        ];

        $typeFilter = $type ? [
            'term' => [
                'type' => $type
            ]
        ] : [];

        if (strlen($keyword)) {
            $query = $typeFilter ? [
                "bool" => [
                    'must' => [
                        'multi_match' => [
                            'query' => $keyword,
                            'fields' => ['title', 'tags', 'content'],
                        ],
                    ],
                    'filter' => $typeFilter,
                ],
            ] : [
                'multi_match' => [
                    'query' => $keyword,
                    'fields' => ['title', 'tags', 'content'],
                ],
            ];

        } else {
            $query = $typeFilter ? [
                "bool" => [
                    'filter' => $typeFilter
                ]
            ] : [
                'match_all' => new \stdClass()
            ];
        }

        $body = [
            'query' => $query,
            'highlight' => [
                'fields' => [
                    'content' => [
                        "order" => "_score",
                        "fragment_size" => 20000,
                        "number_of_fragments" => 1
                    ]
                ]
            ],
            'sort' => $sort,
        ];

        $params = [
            'index' => self::_INDEX_,
            'scroll' => '30s',
            'size'   => $size,
            'body'  => $body
        ];

        $response = $client->search($params);
        $list = $response['hits']['hits'] ?? [];
        $total = $response['hits']['total']['value'] ?? 0;

        $list = array_map(function($v){
            $source = $v['_source'] ?? [];
            $highlight = $v['highlight']['content'][0] ?? '';
            if (strlen($highlight)) $source['content'] = $highlight;
            return $source;
        }, $list);

        if ($p > 1 && $p <= ceil($total / $size)) {
            $i = 1;
            while (isset($response['hits']['hits']) && count($response['hits']['hits']) > 0) {
                $i ++;
                $scroll_id = $response['_scroll_id'];

                $response = $client->scroll([
                        'scroll_id' => $scroll_id,  //...using our previously obtained _scroll_id
                        'scroll'    => '30s'        // and the same timeout window
                    ]
                );

                $tempList = $response['hits']['hits'] ?? [];
                $tempList = array_map(function($v){
                    $source = $v['_source'] ?? [];
                    $highlight = $v['highlight']['content'][0] ?? '';
                    if (strlen($highlight)) $source['content'] = $highlight;
                    return $source;
                }, $tempList);

//                $list = array_merge($list, $tempList);
                if ($p == $i) {
                    $list = $tempList;
                    break;
                }
            }
        }


        return compact('list', 'total', 'size');
    }

    public static function __callStatic($name, $arguments)
    {

        // TODO: Implement __callStatic() method.
        return self::main([self::class, "_" . $name], $arguments);
    }
}